package com.alogic.xscript.plugins;

import com.alogic.xscript.AbstractLogiclet;
import com.alogic.xscript.ExecuteWatcher;
import com.alogic.xscript.Logiclet;
import com.alogic.xscript.LogicletContext;
import com.alogic.xscript.doc.XsObject;
import com.anysoft.util.*;
import org.apache.commons.lang3.StringUtils;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;

/**
 * URL追加器
 *
 * @since 1.6.12.17
 */
public class UrlAppender extends AbstractLogiclet {
    /**
     * 输出变量id
     */
    protected String $id;

    /**
     * URL的前缀
     */
    protected String $base = "";

    protected String encoding = "utf-8";

    /**
     * 是否append到hash端
     */
    protected boolean toHash = false;

    /**
     * 表单数据
     */
    protected List<Pair<String,String>> paraData = new ArrayList<Pair<String,String>>();

    public UrlAppender(String tag, Logiclet p) {
        super(tag, p);
    }

    @Override
    public void configure(Properties p){
        super.configure(p);
        $id = PropertiesConstants.getString(p,"id","$" + this.getXmlTag(),true);
        $base = PropertiesConstants.getRaw(p,"base",$base);
        encoding = PropertiesConstants.getString(p, "encoding", encoding);
        toHash = PropertiesConstants.getBoolean(p,"toHash",toHash);
    }

    @Override
    public void configure(Element e, Properties p) {
        Properties props = new XmlElementProperties(e,p);
        configure(props);

        NodeList nodeList = XmlTools.getNodeListByPath(e, "param");
        for (int i = 0 ;i < nodeList.getLength() ; i ++){
            Node n = nodeList.item(i);
            if (n.getNodeType() != Node.ELEMENT_NODE){
                continue;
            }

            Element elem = (Element)n;
            String id = elem.getAttribute("id");
            String value = elem.getAttribute("value");
            if (StringUtils.isNotEmpty(id) && StringUtils.isNotEmpty(value)){
                paraData.add(new Pair.Default<String,String>(id,value));
            }
        }
    }

    @Override
    protected void onExecute(final XsObject root, final XsObject current, final LogicletContext ctx,
                             final ExecuteWatcher watcher) {
        String id = PropertiesConstants.transform(ctx,$id,"");
        if (StringUtils.isNotEmpty(id)){
            String base = PropertiesConstants.transform(ctx,$base,"");

            String segmentQuery;
            String segmentHash;

            int index = base.indexOf('#');
            if (index < 0){
                segmentQuery = base;
                segmentHash = "";
            }else{
                segmentQuery = base.substring(0,index);
                segmentHash = base.substring(index + 1);
            }

            StringBuffer buffer = new StringBuffer(base.length());

            if (toHash){
                buffer.append(segmentQuery);
                buffer.append("#");
            }

            String src = toHash ? segmentHash : segmentQuery;

            int pos = src.indexOf('?');
            if (pos < 0){
                buffer.append(src);
                buffer.append("?");
            }else{
                buffer.append(src.substring(0,pos));
                buffer.append("?");
            }

            boolean first = true;
            for (Pair<String,String> p:paraData){
                String key = p.key();
                String value = ctx.transform(p.value());
                if (StringUtils.isNotEmpty(value)){
                    try {
                        if (!first){
                            buffer.append("&");
                        }
                        String encodeValue = URLEncoder.encode(value, encoding);
                        buffer.append(key).append("=").append(encodeValue);
                        first = false;
                    } catch (UnsupportedEncodingException e) {
                        log(String.format("Encoding %s is not supported", encoding));
                    }
                }
            }

            if (pos >= 0) {
                String left = src.substring(pos + 1);
                if (StringUtils.isNotEmpty(left)) {
                    buffer.append("&").append(left);
                }
            }

            if (!toHash && StringUtils.isNotEmpty(segmentHash)){
                buffer.append("#");
                buffer.append(segmentHash);
            }
            ctx.SetValue(id, buffer.toString());
        }
    }

}
